package com.yunji.storage.business;

import com.yunji.base.cache.BaseCache;
import com.yunji.base.domain.BelongDO;
import com.yunji.base.enums.AuditStatus;
import com.yunji.base.enums.SystemName;
import com.yunji.base.service.BelongService;
import com.yunji.common.base.BaseBusiness;
import com.yunji.common.enums.business.StorageStatus;
import com.yunji.common.enums.business.StorageType;
import com.yunji.common.enums.common.ErrorEnum;
import com.yunji.common.enums.common.UserType;
import com.yunji.common.model.dto.LoginInfo;
import com.yunji.common.utils.DecimalUtils;
import com.yunji.common.utils.TimeUtils;
import com.yunji.common.utils.bean.BeanUtils;
import com.yunji.common.utils.uuid.UUIDUtils;
import com.yunji.storage.bo.*;
import com.yunji.storage.domain.StockTakeDO;
import com.yunji.storage.domain.StockTakeInfoDO;
import com.yunji.storage.domain.StorageRecordsDO;
import com.yunji.storage.domain.StorageTicketDO;
import com.yunji.storage.dto.StockDTO;
import com.yunji.storage.dto.StockTakeDTO;
import com.yunji.storage.dto.StorageOperateDTO;
import com.yunji.storage.enums.*;
import com.yunji.storage.service.IStockTakeInfoService;
import com.yunji.storage.service.IStockTakeService;
import com.yunji.storage.service.IStorageRecordsService;
import com.yunji.storage.service.IStorageTicketService;
import com.yunji.storage.vo.StockTakeVO;
import com.yunji.system.service.TokenService;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @Project: yunji-coffee
 * @Package: com.yunji.storage.business
 * @Title: StockTakeBusiness
 * <p>
 * History:
 * Date                     Version     Author          Summary
 * ============================================================
 * 2024-08-30 10:07:28      V1.0        HuaAo       新建类
 */
@Component
public class StockTakeBusiness extends BaseBusiness {

    @Resource
    IStockTakeService stockTakeService;

    @Resource
    IStockTakeInfoService stockTakeInfoService;

    @Resource
    IStorageTicketService storageTicketService;

    @Resource
    IStorageRecordsService storageRecordsService;

    @Resource
    StorageInteractBusiness interactBusiness;

    @Resource
    BelongService belongService;

    @Resource
    TokenService tokenService;

    /**
     * @param stockTakeId 盘点单ID
     * @Title select
     * @Desc 盘点单详情
     * @Date 2024-08-30 15:37:08.338
     * @Return StockTakeVO 返还参数
     */
    public StockTakeVO select(Long stockTakeId) {
        StockTakeVO vo = new StockTakeVO();
        StockTakeDO stockTake = stockTakeService.select(stockTakeId);
        if (BeanUtils.isNull(stockTake)) {
            return null;
        }
        BeanUtils.clone(stockTake, vo);
        vo.setBelongName(BaseCache.getBelongName(vo.getBelongId()));
        vo.setParentId(BaseCache.getBelong(vo.getBelongId()).getParentId());
        StockTakeInfoListQueryBO param = new StockTakeInfoListQueryBO();
        param.setStocktakeId(stockTakeId);
        List<StockTakeInfoDO> infoList = stockTakeInfoService.search(param);
        vo.setInfoList(infoList);
        boolean example = true;
        for (StockTakeInfoDO infoDO : infoList) {
            if (!StockTakeResult.EQUALITY.getCode().equals(infoDO.getStocktakeResult())) example = false;
        }
        vo.setExample(example);

        return vo;
    }

    /**
     * @param dto 盘点单参数
     * @Title create
     * @Desc 新增盘点单
     * @Date 2024-08-30 15:50:54.307
     */
    @Transactional
    public Long create(StockTakeDTO dto) {
        logs.info("【新增盘点单】盘点信息:{}", dto);
        checkStockTake(dto);

        LoginInfo user = tokenService.getUser();
        Long belongId = user.getBelongId();
        Assert.isTrue(BeanUtils.isNotNull(belongId), ErrorEnum.BUSINESS_121003.getText());
        logs.info("【新增盘点单】当前用户所属ID:{}", belongId);
        BelongDO belong = belongService.getById(belongId);
        Assert.isTrue(BeanUtils.isNotNull(belong), ErrorEnum.BUSINESS_121004.getText());

        StockTakeDO stockTake = new StockTakeDO();
        BeanUtils.clone(dto, stockTake);
        stockTake.setBelongId(belongId);
        stockTake.setApplyId(user.getUserId());
        stockTake.setApplyName(user.getNickname());
        stockTake.setApplyBelongId(belong.getBelongId());
        stockTake.setApplyBelongName(belong.getBelongName());


        String stockTakeCode = UUIDUtils.stockTakeCode();
        logs.info("【新增盘点单】盘点单号:{}", stockTakeCode);
        stockTake.setStocktakeStatus(StockTakeStatus.WAIT.getCode());
        Date time = TimeUtils.getNowDate();
        logs.info("【新增盘点单】提交时间:{}", time);
        stockTake.setCommitTime(time);
        stockTake.setStocktakeCode(stockTakeCode);
        Assert.isTrue(stockTakeService.create(stockTake), "新增失败");

        //处理盘点详情
        handleInfoList(stockTake, dto.getInfoList(), true);

        return stockTake.getStocktakeId();
    }

    /**
     * @param dto 录入参数
     * @Title recordOperate
     * @Desc 盘点操作
     * @Date 2024-08-30 16:56:22.419
     */
    @Transactional
    public void operate(StockTakeDTO dto) {
        Long stockTakeId = dto.getStocktakeId();
        logs.info("【盘点操作】盘点单ID:{}", stockTakeId);
        Assert.isTrue(BeanUtils.isNotNull(stockTakeId), ErrorEnum.BUSINESS_812009.getText());

        StockTakeDO vo = stockTakeService.select(stockTakeId);
        Integer ordinalStatus = vo.getStocktakeStatus();
        logs.info("【盘点操作】操作前状态:{}", ordinalStatus);
        Assert.isTrue(BeanUtils.equals(ordinalStatus, StockTakeStatus.WAIT.getCode(), StockTakeStatus.PROCEED.getCode(), StockTakeStatus.CANCEL.getCode()), "当前状态不可操作盘点");

        Long dtoBelongId = dto.getBelongId();
        logs.info("【盘点操作】盘点单位:{}", dtoBelongId);
        Assert.isTrue(BeanUtils.isNotNull(dtoBelongId), "请传入盘点单位");

        Integer stockTakeStatus = dto.getStocktakeStatus();
        logs.info("【盘点操作】盘点状态/动作:{}", stockTakeStatus);
        Assert.isTrue(BeanUtils.isNotNull(stockTakeStatus), "请传入盘点状态");

        List<StockTakeInfoDO> infoList = dto.getInfoList();
        logs.info("【盘点操作】商品信息:{}", infoList);
        Assert.isTrue(BeanUtils.isNotNull(infoList), "请传入商品信息");

        Date startTime = dto.getStartTime();
        logs.info("【盘点操作】盘点开始时间:{}", startTime);
        Assert.isTrue(BeanUtils.isNotNull(startTime), "请输入开始时间");

        List<StockTakeInfoDO> updateList = new ArrayList<>();
        for (StockTakeInfoDO stockTakeInfo : infoList) {

            String productName = stockTakeInfo.getProductName();
            BigDecimal expectQuantity = stockTakeInfo.getExpectQuantity();
            logs.info("【盘点操作】{}账面可用库存:{}", productName, expectQuantity);
            BigDecimal actualQuantity = stockTakeInfo.getActualQuantity();
            logs.info("【盘点操作】{}实际可用库存：{}", productName, actualQuantity);

            // 完成盘点必须要有实际可用库存
            if (Objects.equals(StockTakeStatus.OVER.getCode(), stockTakeStatus)) {
                Assert.isTrue(BeanUtils.isNotNull(actualQuantity), ErrorEnum.CHECKED_811023.getText());
            }
            //计算盘亏盘盈
            if (BeanUtils.isNotNull(actualQuantity)) {
                handleInfoQuantity(stockTakeInfo, expectQuantity, actualQuantity);
                updateList.add(stockTakeInfo);
            } else {
                // 否则就滞空
                Assert.isTrue(stockTakeInfoService.cleanData(stockTakeInfo.getInfoId()), "修改失败");
            }
        }

        for (StockTakeInfoDO stockTakeInfo : updateList) {
            stockTakeInfoService.update(stockTakeInfo);
        }

        LoginInfo user = tokenService.getUser();
        String userType = user.getUserType();
        Long belongId = user.getBelongId();
        Assert.isTrue(BeanUtils.isNotNull(belongId), ErrorEnum.BUSINESS_121003.getText());
        logs.info("【盘点操作】当前用户类型:{},当前用户所属ID:{}", userType, belongId);


        BelongDO belongVO = belongService.getById(belongId);
        logs.info("【盘点操作】当前用户所属信息:{}", belongVO);
        Assert.isTrue(BeanUtils.isNotNull(belongVO), ErrorEnum.BUSINESS_121004.getText());

        StockTakeResetBO reset = new StockTakeResetBO();
        reset.setStockTakeId(stockTakeId);
        reset.setAuditStatus(AuditStatus.ACCEPT.getCode());
        reset.setAuditId(user.getUserId());
        reset.setAuditName(user.getNickname());
        reset.setAuditBelongId(belongId);
        reset.setAuditBelongName(belongVO.getBelongName());
        reset.setAuditTime(TimeUtils.getNowDate());
        stockTakeService.reset(reset);

        StockTakeDO update = new StockTakeDO();
        update.setStocktakeId(stockTakeId);
        update.setStocktakeStatus(stockTakeStatus);
        update.setStartTime(startTime);
        update.setRemark(dto.getRemark());

        if (Objects.equals(StockTakeStatus.OVER.getCode(), stockTakeStatus)) {

            update.setApplyId(user.getUserId());
            update.setApplyName(user.getNickname());
            update.setApplyBelongId(belongId);
            update.setApplyBelongName(belongVO.getBelongName());
            update.setApplyTime(TimeUtils.getNowDate());

            StorageUpdateAuditBO auditBO = new StorageUpdateAuditBO();
            auditBO.setBusinessId(stockTakeId);
            auditBO.setAuditStatus(AuditStatus.WAIT.getCode());

            boolean example = true;
            for (StockTakeInfoDO infoDO : updateList) {
                 if (!StockTakeResult.EQUALITY.getCode().equals(infoDO.getStocktakeResult())) example = false;
            }

            if (Objects.equals(UserType.PLATE.getCode(), userType) || example) {
                // 管理员完成盘点 不需要审核
                auditBO.setAuditId(user.getUserId());
                auditBO.setAuditName(user.getNickname());
                auditBO.setAuditBelongId(belongVO.getBelongId());
                auditBO.setAuditBelongName(SystemName.ENABLED.getText());
                if (example){
                    auditBO.setAuditId(1L);
                    auditBO.setAuditName("平台");
                    auditBO.setAuditBelongId(1L);
                    auditBO.setAuditBelongName(SystemName.ENABLED.getText());
                }
                auditBO.setAuditStatus(AuditStatus.ACCEPT.getCode());
                auditBO.setAuditTime(TimeUtils.getNowDate());
                update.setStocktakeStatus(StockTakeStatus.FINISH.getCode());

                BeanUtils.clone(dto, vo);
                handleAcceptAudit(vo, update);
            }

            stockTakeService.updateAuditStatus(auditBO);

        }
        Assert.isTrue(stockTakeService.update(update), "修改失败");
    }

    /**
     * @param stockTakeId 盘点ID
     * @param auditStatus 审核状态
     * @param reason      驳回原因
     * @Title audit
     * @Desc 盘点审核
     * @Date 2024-08-31 10:46:28.252
     */
    @Transactional
    public void audit(Long stockTakeId, Integer auditStatus, String reason) {
        LoginInfo user = tokenService.getUser();
        Long belongId = user.getBelongId();
        logs.info("【审核盘点单】当前用户所属ID:{}", belongId);
        Assert.isTrue(BeanUtils.isNotNull(belongId), ErrorEnum.BUSINESS_121003.getText());


        BelongDO belongVO = belongService.getById(belongId);
        logs.info("【审核盘点单】当前用户所属信息:{}", belongVO);
        Assert.isTrue(BeanUtils.isNotNull(belongVO), ErrorEnum.BUSINESS_121004.getText());

        logs.info("【审核盘点单】报废单ID:{}", stockTakeId);
        StockTakeDO stockTake = stockTakeService.select(stockTakeId);
        logs.info("【审核盘点单】盘点单信息:{}", stockTake);
        Assert.isTrue(BeanUtils.isNotNull(stockTake), ErrorEnum.BUSINESS_812009.getText());
        Assert.isTrue(Objects.equals(AuditStatus.WAIT.getCode(), stockTake.getAuditStatus()), ErrorEnum.BUSINESS_812005.getText());

        StockTakeDO update = new StockTakeDO();
        update.setStocktakeId(stockTakeId);
        update.setAuditId(user.getUserId());
        update.setAuditName(user.getNickname());
        update.setAuditBelongId(belongVO.getBelongId());
        update.setAuditBelongName(belongVO.getBelongName());
        update.setAuditStatus(auditStatus);

        Date time = TimeUtils.getNowDate();
        update.setAuditTime(time);


        if (Objects.equals(AuditStatus.ACCEPT.getCode(), auditStatus)) {

            // 审核通过 根据商品详情生成出入库单据
            handleAcceptAudit(stockTake, update);

        } else {
            // 审核驳回变成已取消状态
            if (BeanUtils.isNotNull(reason)) {
                update.setReason(reason);
            }
            update.setStocktakeStatus(StockTakeStatus.CANCEL.getCode());
        }

        StorageUpdateAuditBO auditBO = new StorageUpdateAuditBO();
        auditBO.setBusinessId(stockTakeId);
        auditBO.setAuditStatus(auditStatus);
        Assert.isTrue(stockTakeService.updateAuditStatus(auditBO),"修改失败");
        Assert.isTrue(stockTakeService.update(update), "修改失败");
    }

    /**
     * @param stockTakeId 盘点单ID
     * @Title cancel
     * @Desc 取消盘点单
     * @Date 2024-08-31 14:39:00.895
     */
    public void cancel(Long stockTakeId) {
        StockTakeDO take = stockTakeService.select(stockTakeId);
        logs.info("【取消盘点单】盘点单信息:{}", take);
        Assert.isTrue(BeanUtils.isNotNull(take), ErrorEnum.BUSINESS_812009.getText());

        Integer stockTakeStatus = take.getStocktakeStatus();
        Assert.isTrue(Objects.equals(StockTakeStatus.OVER.getCode(), stockTakeStatus), "当前状态不可取消");

        // 变成已取消状态 无其他变化

        StockTakeDO update = new StockTakeDO();
        update.setStocktakeId(stockTakeId);
        update.setStocktakeStatus(StockTakeStatus.CANCEL.getCode());

        Assert.isTrue(stockTakeService.update(update), "修改失败");

        StockTakeResetBO reset = new StockTakeResetBO();
        reset.setStockTakeId(stockTakeId);
        reset.setAuditStatus(AuditStatus.WAIT.getCode());
        stockTakeService.reset(reset);

    }

    /**
     * @param dto 盘点参数
     * @Title commit
     * @Desc 重新提交盘点单
     * @Date 2024-08-31 14:58:30.710
     */
    @Transactional
    public void commit(StockTakeDTO dto) {
        logs.info("【重新提交盘点单】盘点单信息:{}", dto);
        checkStockTake(dto);

        Long stockTakeId = dto.getStocktakeId();
        Assert.isTrue(BeanUtils.isNotNull(stockTakeId), "未找到盘点单ID");

        Integer stockTakeStatus = dto.getStocktakeStatus();
        logs.info("【重新提交盘点单】盘点单状态:{}", stockTakeStatus);
        Assert.isTrue(BeanUtils.equals(stockTakeStatus, StockTakeStatus.DRAFT.getCode(), StockTakeStatus.CANCEL.getCode()), "当前状态不可提交");

        LoginInfo user = tokenService.getUser();
        Long belongId = user.getBelongId();
        logs.info("【重新提交盘点单】当前用户所属ID:{}", belongId);
        Assert.isTrue(BeanUtils.isNotNull(belongId), ErrorEnum.BUSINESS_121003.getText());

        StockTakeDO stockTake = new StockTakeDO();

        Date time = TimeUtils.getNowDate();
        logs.info("【重新提交盘点单】提交时间:{}", time);
        stockTake.setStocktakeId(dto.getStocktakeId());
        stockTake.setStocktakeCode(dto.getStocktakeCode());
        stockTake.setCommitTime(time);
        stockTake.setStocktakeStatus(StockTakeStatus.WAIT.getCode());
        stockTake.setStocktakeTitle(dto.getStocktakeTitle());
        stockTake.setStocktakeType(dto.getStocktakeType());
        stockTake.setRemark(dto.getRemark());

        Integer auditStatus = dto.getAuditStatus();

        if (Objects.equals(StockTakeStatus.CANCEL.getCode(), stockTakeStatus) && BeanUtils.isNotNull(auditStatus)) {
            // 盘点状态 - 已取消状态
            // 审核状态 - 通过
            //        - 驳回
            // 重新生成单据
            String stockTakeCode = UUIDUtils.stockTakeCode();
            stockTake.setStocktakeCode(stockTakeCode);
            handleCancelTicket(dto, stockTake);
        } else {
            // 盘点状态  - 草稿状态
            //         - 已取消状态
            // 审核状态  - 空
            // 提交原来单据
            Assert.isTrue(stockTakeService.update(stockTake), "修改失败");
            handleInfoList(stockTake, dto.getInfoList(), true);
        }
    }

    /**
     * @param dto 盘点DTO
     * @Title saveDraft
     * @Desc 保存草稿
     * @Date 2024-08-30 10:40:58.720
     */
    @Transactional
    public void saveDraft(StockTakeDTO dto) {
        logs.info("【保存草稿】草稿信息:{}", dto);

        LoginInfo user = tokenService.getUser();
        Long belongId = user.getBelongId();
        logs.info("【保存草稿】当前用户所属ID:{}", belongId);
        Assert.isTrue(BeanUtils.isNotNull(belongId), ErrorEnum.BUSINESS_121003.getText());

        StockTakeDO stockTake = new StockTakeDO();
        BeanUtils.clone(dto, stockTake);
        String stockTakeCode = UUIDUtils.stockTakeCode();
        logs.info("【保存草稿】盘点单号:{}", stockTakeCode);

        Integer stockTakeStatus = StockTakeStatus.DRAFT.getCode();

        // 删除当前用户之前的草稿
        StockTakeDO delete = new StockTakeDO();
        delete.setBelongId(belongId);
        delete.setStocktakeStatus(stockTakeStatus);
        stockTakeService.deleteByTicket(new StockTakeRemoveBO(belongId, stockTakeStatus));

        stockTake.setBelongId(belongId);
        stockTake.setStocktakeStatus(stockTakeStatus);
        stockTake.setStocktakeCode(stockTakeCode);
        Assert.isTrue(stockTakeService.create(stockTake), "新增失败");

        Long stockTakeId = stockTake.getStocktakeId();
        logs.info("【保存草稿】盘点单ID:{}", stockTakeId);

        // 处理坏返单详情
        if (BeanUtils.isNotNull(dto.getInfoList())) {
            handleInfoList(stockTake, dto.getInfoList(), false);
        }
    }

    /**
     * @param belongId 所属单位ID
     * @Title getDraft
     * @Desc 获取草稿
     * @Date 2024-08-30 14:27:02.055
     * @Return RepairTicketVO 草稿信息
     */
    public StockTakeVO getDraft(Long belongId) {

        StockTakeDO stockTake = stockTakeService.select(new StockTakeSelectQueryBO(belongId, RepairStatus.DRAFT.getCode()));
        StockTakeVO vo = new StockTakeVO();
        if (BeanUtils.isNotNull(stockTake)) {
            BeanUtils.clone(stockTake, vo);
        }

        Long stockTakeId = vo.getStocktakeId();
        logs.info("【获取草稿】盘点单ID:{}", stockTakeId);

        if (BeanUtils.isNotNull(stockTakeId)) {
            StockTakeInfoListQueryBO param = new StockTakeInfoListQueryBO();
            param.setStocktakeId(vo.getStocktakeId());
            List<StockTakeInfoDO> infoList = stockTakeInfoService.search(param);
            vo.setInfoList(infoList);
            vo.setDraftStatus(DraftStatus.EXIST.getCode());
        } else {
            vo.setDraftStatus(DraftStatus.ABSENT.getCode());
        }

        return vo;
    }

    /**
     * @param stockTakeIds 盘点单Ids
     * @Title delete
     * @Desc 删除盘点单
     * @Date 2024-08-30 16:16:17.419
     */
    @Transactional
    public void delete(Long... stockTakeIds) {
        stockTakeService.delete(stockTakeIds);
        stockTakeInfoService.deleteByStockTakeIds(stockTakeIds);
    }

    /*--------------------------------------------方法/参数校验------------------------------------------*/

    /**
     * @param update      更新状态的盘点单
     * @Title handleAcceptAudit
     * @Desc 处理审核通过的盘点单
     * @Date 2024-09-02 14:08:08.556
     */
    private void handleAcceptAudit(StockTakeDO stockTake, StockTakeDO update) {
        StockTakeInfoListQueryBO param = new StockTakeInfoListQueryBO();
        param.setStocktakeId(stockTake.getStocktakeId());
        List<StockTakeInfoDO> infoList = stockTakeInfoService.search(param);

        List<StockTakeInfoDO> intoList = new ArrayList<>();
        List<StockTakeInfoDO> outList = new ArrayList<>();

        for (StockTakeInfoDO stockTakeInfo : infoList) {
            Integer stockTakeResult = stockTakeInfo.getStocktakeResult();
            logs.info("【审核盘点单】盘点结果:{}", stockTakeResult);

            if (Objects.equals(StockTakeResult.MORE.getCode(), stockTakeResult)) {
                intoList.add(stockTakeInfo);
            }
            if (Objects.equals(StockTakeResult.LESS.getCode(), stockTakeResult)) {
                outList.add(stockTakeInfo);
            }
        }

        // 盘盈 入库
        handleRepairStorageTicket(stockTake, intoList, StorageType.INTO_STORAGE.getCode());
        // 盘亏 出库
        handleRepairStorageTicket(stockTake, outList, StorageType.OUT_STORAGE.getCode());

        update.setStocktakeStatus(StockTakeStatus.FINISH.getCode());
    }

    /**
     * @Title handleInfoList
     * @Desc 处理盘点详情
     * @Date 2024-08-30 10:59:12.307
     */
    private void handleInfoList(StockTakeDO stockTake, List<StockTakeInfoDO> infoList, boolean checkStatus) {
        // 先查出来所有  没有就新增 有就修改  其他删除
        StockTakeInfoListQueryBO param = new StockTakeInfoListQueryBO();
        param.setStocktakeId(stockTake.getStocktakeId());
        List<StockTakeInfoDO> list = stockTakeInfoService.search(param);
        logs.info("【处理盘点单详情】存在的详情:{}", list);

        List<StockTakeInfoDO> createList = new ArrayList<>();
        List<StockTakeInfoDO> updateList = new ArrayList<>();
        List<Long> deleteIds = new ArrayList<>();

        // 获取当前详情
        for (StockTakeInfoDO stockTakeInfo : list) {
            deleteIds.add(stockTakeInfo.getInfoId());
        }

        // 处理详情
        for (StockTakeInfoDO stockTakeInfo : infoList) {
            stockTakeInfo.setBelongId(stockTake.getBelongId());
            stockTakeInfo.setStocktakeId(stockTake.getStocktakeId());
            stockTakeInfo.setStocktakeCode(stockTake.getStocktakeCode());
            // 非草稿状态都需要检验
            if (checkStatus) {
                checkStockTakeInfo(stockTakeInfo);
            }
            // 进行修改的详情
            Long infoId = stockTakeInfo.getInfoId();
            logs.info("【处理盘点单详情】详情ID:{}", infoId);
            if (BeanUtils.isNotNull(stockTakeInfo.getInfoId())) {
                // 进行修改的剔除删除行列
                updateList.add(stockTakeInfo);
                if (deleteIds.contains(infoId)) {
                    deleteIds.remove(infoId);
                }
            } else {
                createList.add(stockTakeInfo);
            }
        }

        logs.info("【处理盘点单详情】删除详情Ids:{}", deleteIds);
        stockTakeInfoService.delete(deleteIds);

        logs.info("【处理盘点单详情】新增盘点单详情:{}", createList);
        for (StockTakeInfoDO create : createList) {
            Assert.isTrue(stockTakeInfoService.create(create), "新增失败");
        }

        logs.info("【处理盘点单详情】修改盘点单详情:{}", updateList);
        for (StockTakeInfoDO update : updateList) {
            stockTakeInfoService.update(update);
        }
    }

    /**
     * @param dto       重新提交信息
     * @param stockTake 新盘点单
     * @Title handleCancelTicket
     * @Desc 处理取消状态盘点单
     * @Date 2024-08-31 16:04:15.915
     */
    private void handleCancelTicket(StockTakeDTO dto, StockTakeDO stockTake) {
        Long stockTakeId = dto.getStocktakeId();
        logs.info("【处理取消状态盘点单】单据ID:{}", stockTakeId);
        Integer stockTakeStatus = StockTakeStatus.SCRAP.getCode();
        StockTakeDO update = new StockTakeDO();
        update.setStocktakeId(stockTakeId);
        update.setStocktakeStatus(stockTakeStatus);
        Assert.isTrue(stockTakeService.update(update), "修改失败");

        stockTake.setStocktakeId(null);
        Assert.isTrue(stockTakeService.create(stockTake), "新增失败");

        List<StockTakeInfoDO> infoList = dto.getInfoList();
        logs.info("【处理取消状态盘点单】商品信息:{}", infoList);

        List<StockTakeInfoDO> createList = new ArrayList<>();

        for (StockTakeInfoDO stockTakeInfo : infoList) {
            checkStockTakeInfo(stockTakeInfo);

            StockTakeInfoDO info = new StockTakeInfoDO();
            BeanUtils.clone(stockTakeInfo, info);

            info.setStocktakeId(stockTake.getStocktakeId());
            info.setStocktakeCode(stockTake.getStocktakeCode());
            createList.add(info);
        }

        for (StockTakeInfoDO create : createList) {
            Assert.isTrue(stockTakeInfoService.create(create), "新增失败");
        }

    }

    /**
     * @Title handleStorageTicket
     * @Desc 生成单据，处理库存
     * @Date 2024-08-31 11:01:11.075
     */
    private void handleRepairStorageTicket(StockTakeDO stockTake, List<StockTakeInfoDO> infoList, Integer storageType) {
        if (BeanUtils.isNull(infoList)) {
            return;
        }

        StorageTicketDO storageTicket = new StorageTicketDO();
        List<StorageRecordsDO> recordsList = new ArrayList<>();

        Long stockTakeId = stockTake.getStocktakeId();
        logs.info("【处理出入库单据】业务ID:{}", stockTakeId);

        String stockTakeCode = stockTake.getStocktakeCode();
        logs.info("【处理出入库单据】业务单号:{}", stockTakeCode);

        Integer businessType = StorageBusinessType.STOCKTAKE_BUSINESS.getCode();
        logs.info("【处理出入库单据】业务类型:{}", businessType);

        storageTicket.setBusinessId(stockTakeId);
        storageTicket.setBusinessCode(stockTakeCode);
        storageTicket.setBusinessType(businessType);
        storageTicket.setStorageType(storageType);
        storageTicket.setBelongId(stockTake.getBelongId());
        storageTicket.setDeletable(DeletableStatus.CAN_NOT.getCode());
        storageTicket.setOperateTime(TimeUtils.getNowDate());
        storageTicket.setOperateName(SystemName.ENABLED.getText());
        storageTicket.setStorageStatus(StorageStatus.ALREADY_STORAGE.getCode());

        if (Objects.equals(StorageType.INTO_STORAGE.getCode(), storageType)) {
            String ticketCode = UUIDUtils.intoStorageCode();
            logs.info("【处理出入库单据】入库单据Code:{}", ticketCode);
            storageTicket.setTicketCode(ticketCode);
        } else {
            String ticketCode = UUIDUtils.outStorageCode();
            logs.info("【处理出入库单据】出库据Code:{}", ticketCode);
            storageTicket.setTicketCode(ticketCode);
        }

        //库存操作参数
        StorageOperateDTO operateDTO = new StorageOperateDTO();
        List<StockDTO> dtoList = new ArrayList<>();
        operateDTO.setBelongId(stockTake.getBelongId());
        operateDTO.setStorageType(storageType);
        operateDTO.setBusinessType(StorageBusinessType.STOCKTAKE_BUSINESS.getCode());
        operateDTO.setBusinessCode(stockTakeCode);

        logs.info("【处理出入库单据】出入库单据信息:{}", storageTicket);
        Assert.isTrue(storageTicketService.create(storageTicket), "新增失败");

        for (StockTakeInfoDO info : infoList) {
            StorageRecordsDO storageRecords = new StorageRecordsDO();

            BeanUtils.clone(info, storageRecords);
            BeanUtils.clone(storageTicket, storageRecords);

            BigDecimal amount = info.getStocktakeDeviate().abs();
            logs.info("【处理出入库单据】坏返数量:{}", amount);
            storageRecords.setExpectQuantity(amount);
            storageRecords.setActualQuantity(amount);
            storageRecords.setOperateTime(TimeUtils.getNowDate());

            StockDTO stockDTO = new StockDTO();
            stockDTO.setProductId(info.getProductId());
            stockDTO.setActualQuantity(amount);

            recordsList.add(storageRecords);
            dtoList.add(stockDTO);

        }

        logs.info("【处理出入库单据】出入库记录:{}", recordsList);
        for (StorageRecordsDO storageRecords : recordsList) {
            Assert.isTrue(storageRecordsService.create(storageRecords), "新增失败");
        }

        operateDTO.setList(dtoList);
        interactBusiness.operateStorage(operateDTO);

    }

    /**
     * @Title handleInfo
     * @Desc 处理盘点数据
     * @Date 2024-08-30 18:22:48.942
     */
    private void handleInfoQuantity(StockTakeInfoDO info, BigDecimal expect, BigDecimal actual) {
        Integer stockTakeResult = StockTakeResult.EQUALITY.getCode();

        // 差异数量
        BigDecimal deviate = actual.subtract(expect);

        if (DecimalUtils.more(deviate, BigDecimal.ZERO)) {
            stockTakeResult = StockTakeResult.MORE.getCode();
        }
        if (DecimalUtils.less(deviate, BigDecimal.ZERO)) {
            stockTakeResult = StockTakeResult.LESS.getCode();
        }

        info.setStocktakeResult(stockTakeResult);
        info.setStocktakeDeviate(deviate);
    }

    /**
     * @param dto 盘点参数
     * @Title checkStockTake
     * @Desc 校验盘点参数
     * @Date 2024-08-30 15:52:20.482
     */
    private void checkStockTake(StockTakeDTO dto) {
        String stockTakeTitle = dto.getStocktakeTitle();
        Integer stockTakeType = dto.getStocktakeType();
        List<StockTakeInfoDO> infoList = dto.getInfoList();

        logs.info("【校验参数】盘点标题:{}", stockTakeTitle);
        logs.info("【校验参数】盘点类型:{}", stockTakeType);
        logs.info("【校验参数】盘点商品:{}", infoList);

        Assert.isTrue(BeanUtils.isNotNull(stockTakeTitle), ErrorEnum.CHECKED_811024.getText());
        Assert.isTrue(BeanUtils.isNotNull(stockTakeType), ErrorEnum.CHECKED_811025.getText());
        Assert.isTrue(BeanUtils.isNotNull(infoList), ErrorEnum.CHECKED_811003.getText());
    }

    /**
     * @param dto 盘点商品
     * @Title checkRepairInfo
     * @Desc 校验盘点商品参数
     * @Date 2024-08-30 11:34:19.639
     */
    private void checkStockTakeInfo(StockTakeInfoDO dto) {
        Long productId = dto.getProductId();
        String productSku = dto.getProductSku();
        String productName = dto.getProductName();
        Long unitId = dto.getUnitId();
        BigDecimal expectQuantity = dto.getExpectQuantity();

        logs.info("【盘点商品校验】商品ID:{}", productId);
        logs.info("【盘点商品校验】商品sku:{}", productSku);
        logs.info("【盘点商品校验】商品名称:{}", productName);
        logs.info("【盘点商品校验】商品单位:{}", unitId);
        logs.info("【盘点商品校验】可用库存:{}", expectQuantity);

        Assert.isTrue(BeanUtils.isNotNull(productId), ErrorEnum.CHECKED_811003.getText());
        Assert.isTrue(BeanUtils.isNotNull(productSku), ErrorEnum.CHECKED_811003.getText());
        Assert.isTrue(BeanUtils.isNotNull(productName), ErrorEnum.CHECKED_811003.getText());
        Assert.isTrue(BeanUtils.isNotNull(unitId), ErrorEnum.CHECKED_811003.getText());
        Assert.isTrue(BeanUtils.isNotNull(expectQuantity), ErrorEnum.CHECKED_811023.getText());
    }

}